import { ComUtils } from "./Com";

export type HttpRequestMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
export type HttpRequestData = { [key: string]: any };

export type HttpHeaders = {
    [key: string]: string
}

export class HttpClient {
    static async httpRequest<T>(method: HttpRequestMethod, path: string, data?: HttpRequestData | FormData | File | Blob, headers?: HttpHeaders, response = false) {
        let url = path
        const init = {
            method,
            headers: {},
        }
        if (/^https?:\/\//.test(path)) {
            url = path
        }

        if (method === 'GET' && data) {
            url += '?' + ComUtils.queryToString(data)
            Reflect.set(init.headers, 'Content-Type', 'application/json')
        } else if (data instanceof FormData || data instanceof File || data instanceof Blob) {
            Reflect.set(init, 'body', data)
        } else {
            const rowBody = typeof data === 'object' ? JSON.stringify(data) : data
            Reflect.set(init, 'body', rowBody)
            Reflect.set(init.headers, 'Content-Type', 'application/json')
        }

        if (headers) {
            for (const k in headers) {
                Reflect.set(init.headers, k, headers[k])
            }
        }

        const res = await fetch(url, init).catch(() => undefined)
        if (!res) {
            throw new Error('net error')
        }
        if (response) {
            return res
        }
        const resData = await res?.json().catch(() => undefined)
        if (resData == undefined) {
            throw new Error('net error')
        }
        return (resData ?? undefined) as T
    }

    static upload<T>(path: string, file: File) {
        return HttpClient.httpRequest<T>('POST', path, file)
    }

    static get<T>(path: string, query?: HttpRequestData, headers?: HttpHeaders) {
        return HttpClient.httpRequest<T>('GET', path, query, headers)
    }

    static post<T>(path: string, data?: HttpRequestData, headers?: HttpHeaders) {
        return HttpClient.httpRequest<T>('POST', path, data, headers)
    }

    static put<T>(path: string, data?: HttpRequestData, headers?: HttpHeaders) {
        return HttpClient.httpRequest<T>('PUT', path, data, headers)
    }

    static delete<T>(path: string, data?: HttpRequestData, headers?: HttpHeaders) {
        return HttpClient.httpRequest<T>('DELETE', path, data, headers)
    }

    static patch<T>(path: string, data?: HttpRequestData, headers?: HttpHeaders) {
        return HttpClient.httpRequest<T>('PATCH', path, data, headers)
    }
}